From fb5dc7384148111bcec2993b853601efe0de5bd1 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Timm=20B=C3=A4der?= Date: Fri, 29 Nov 2019 06:54:43 +0100 Subject: [PATCH] gl renderer: Implement blurred shadow nodes --- gsk/gl/gskglrenderer.c | 121 ++++++++++++++++++++++++++++------------- 1 file changed, 82 insertions(+), 39 deletions(-) diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index 3c874a7450..9f439e5c32 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -64,7 +64,9 @@ typedef enum FORCE_OFFSCREEN = 1 << 0, RESET_CLIP = 1 << 1, RESET_OPACITY = 1 << 2, - DUMP_FRAMEBUFFER = 1 << 3 + DUMP_FRAMEBUFFER = 1 << 3, + CENTER_CHILD = 1 << 4, + NO_CACHE_PLZ = 1 << 5, } OffscreenFlags; typedef struct @@ -1966,31 +1968,16 @@ render_outset_shadow_node (GskGLRenderer *self, } static inline void -render_shadow_node (GskGLRenderer *self, - GskRenderNode *node, - RenderOpBuilder *builder) -{ - float min_x; - float min_y; - float max_x; - float max_y; +render_shadow_node (GskGLRenderer *self, + GskRenderNode *node, + RenderOpBuilder *builder) +{ + const float scale = ops_get_scale (builder); + const gsize n_shadows = gsk_shadow_node_get_n_shadows (node); GskRenderNode *original_child = gsk_shadow_node_get_child (node); GskRenderNode *shadow_child = original_child; - gsize n_shadows = gsk_shadow_node_get_n_shadows (node); guint i; - /* TODO: Implement blurred shadow nodes */; - for (i = 0; i < n_shadows; i ++) - { - const GskShadow *shadow = gsk_shadow_node_peek_shadow (node, i); - - if (shadow->radius > 0) - { - render_fallback_node (self, node, builder); - return; - } - } - /* Shadow nodes recolor every pixel of the source texture, but leave the alpha in tact. * If the child is a color matrix node that doesn't touch the alpha, we can throw that away. */ if (gsk_render_node_get_node_type (shadow_child) == GSK_COLOR_MATRIX_NODE && @@ -1999,11 +1986,6 @@ render_shadow_node (GskGLRenderer *self, shadow_child = gsk_color_matrix_node_get_child (shadow_child); } - min_x = builder->dx + shadow_child->bounds.origin.x; - min_y = builder->dy + shadow_child->bounds.origin.y; - max_x = min_x + shadow_child->bounds.size.width; - max_y = min_y + shadow_child->bounds.size.height; - for (i = 0; i < n_shadows; i ++) { const GskShadow *shadow = gsk_shadow_node_peek_shadow (node, i); @@ -2011,10 +1993,13 @@ render_shadow_node (GskGLRenderer *self, const float dy = shadow->dy; TextureRegion region; gboolean is_offscreen; + float min_x; + float min_y; + float max_x; + float max_y; - g_assert (shadow->radius <= 0); - - if (gsk_render_node_get_node_type (shadow_child) == GSK_TEXT_NODE) + if (shadow->radius == 0 && + gsk_render_node_get_node_type (shadow_child) == GSK_TEXT_NODE) { ops_offset (builder, dx, dy); render_text_node (self, shadow_child, builder, &shadow->color, TRUE); @@ -2028,12 +2013,57 @@ render_shadow_node (GskGLRenderer *self, if (node_is_invisible (shadow_child)) continue; - /* Draw the child offscreen, without the offset. */ - if (!add_offscreen_ops (self, builder, - &shadow_child->bounds, - shadow_child, ®ion, &is_offscreen, - RESET_CLIP | RESET_OPACITY)) - g_assert_not_reached (); + if (shadow->radius > 0) + { + const float blur_extra = shadow->radius * 3.0 / 2.0; + + /* TODO: - same problem as in render_blur_node: we're forcing the + * child node on a texture, even though it might already be a texture. */ + if (!add_offscreen_ops (self, builder, + &GRAPHENE_RECT_INIT ( + 0, 0, + shadow_child->bounds.size.width + (blur_extra * 2), + shadow_child->bounds.size.height + (blur_extra * 2) + ), + shadow_child, ®ion, &is_offscreen, + RESET_CLIP | RESET_OPACITY | CENTER_CHILD | + NO_CACHE_PLZ | FORCE_OFFSCREEN)) + g_assert_not_reached (); + + region.texture_id = blur_texture (self, builder, + ®ion, + (shadow_child->bounds.size.width + blur_extra * 2) * scale, + (shadow_child->bounds.size.height + blur_extra * 2) * scale, + shadow->radius * scale); + init_full_texture_region (®ion, region.texture_id); + + is_offscreen = TRUE; + + min_x = builder->dx + shadow_child->bounds.origin.x - blur_extra; + min_y = builder->dy + shadow_child->bounds.origin.y - blur_extra; + max_x = min_x + shadow_child->bounds.size.width + blur_extra * 2; + max_y = min_y + shadow_child->bounds.size.height + blur_extra * 2; + } + else if (dx == 0 && dy == 0) + { + continue; /* Invisible anyway */ + } + else + { + if (dx == 0 && dy == 0) + continue; + + if (!add_offscreen_ops (self, builder, + &shadow_child->bounds, + shadow_child, ®ion, &is_offscreen, + RESET_CLIP | RESET_OPACITY | NO_CACHE_PLZ)) + g_assert_not_reached (); + + min_x = builder->dx + shadow_child->bounds.origin.x; + min_y = builder->dy + shadow_child->bounds.origin.y; + max_x = min_x + shadow_child->bounds.size.width; + max_y = min_y + shadow_child->bounds.size.height; + } ops_set_program (builder, &self->coloring_program); ops_set_color (builder, &shadow->color); @@ -3131,8 +3161,20 @@ add_offscreen_ops (GskGLRenderer *self, bounds->origin.y * scale, width, height)); - builder->dx = 0; - builder->dy = 0; + if (flags & CENTER_CHILD) + { + ops_offset (builder, + (bounds->size.width - child_node->bounds.size.width) / 2.0 - + child_node->bounds.origin.x, + (bounds->size.height - child_node->bounds.size.height) / 2.0 - + child_node->bounds.origin.y); + } + else + { + builder->dx = 0; + builder->dy = 0; + } + if (flags & RESET_OPACITY) prev_opacity = ops_set_opacity (builder, 1.0); @@ -3167,7 +3209,8 @@ add_offscreen_ops (GskGLRenderer *self, *is_offscreen = TRUE; init_full_texture_region (texture_region_out, texture_id); - gsk_gl_driver_set_texture_for_pointer (self->gl_driver, child_node, texture_id); + if ((flags & NO_CACHE_PLZ) == 0) + gsk_gl_driver_set_texture_for_pointer (self->gl_driver, child_node, texture_id); return TRUE; } -- 2.30.2